﻿using System;
using Microsoft.Xna.Framework.Input;
using Microsoft.Xna.Framework.Input.Touch;
using Syngine.Components;
#if !(WINDOWS_PHONE || ANDROID)
using Syngine.Input.Mouse;
#endif

namespace Syngine.Input
{
	/// <summary>
	/// 
	/// </summary>
	public class UserInput : IUpdate
	{
		#region Fields

		private readonly ActionList _actions = new ActionList();

		#endregion

		#region Constructors

		/// <summary>
		/// 
		/// </summary>
		public UserInput()
		{
			CurrentState = GetInputState();
		}

		#endregion

		#region Properties

		internal ITouchHandler Touch { get; private set; }

		internal IKeyboardHandler Keyboard { get; private set; }

#if !(WINDOWS_PHONE || ANDROID)
		internal IGamePadHandler GamePad { get; private set; }

		internal IMouseHandler Mouse { get; private set; }

		internal IMarqueeHandler Marquee { get; private set; }
#endif

		private InputState CurrentState { get; set; }

		#endregion

		#region Methods

#if !(WINDOWS_PHONE || ANDROID)
		/// <summary>
		/// Sets the specified mouse handler to handle user input.
		/// </summary>
		/// <param name="mouse">The mouse handler.</param>
		public void Set(IMouseHandler mouse)
		{
			Mouse = mouse;
		}

		/// <summary>
		/// Sets the specified marqueue handler to handle user input.
		/// </summary>
		/// <param name="gamePad">The game pad handler.</param>
		public void Set(IMarqueeHandler marquee)
		{
			Marquee = marquee;
		}

		/// <summary>
		/// Sets the specified game pad handler to handle user input.
		/// </summary>
		/// <param name="gamePad">The game pad handler.</param>
		public void Set(IGamePadHandler gamePad)
		{
			GamePad = gamePad;
		}
#endif

		/// <summary>
		/// Sets the specified touch handler to handle user input.
		/// </summary>
		/// <param name="touch">The touch handler.</param>
		public void Set(ITouchHandler touch)
		{
			Touch = touch;
		}

		/// <summary>
		/// Sets the specified keyboard handler to handle user input.
		/// </summary>
		/// <param name="keyboard">The keyboard handler.</param>
		public void Set(IKeyboardHandler keyboard)
		{
			Keyboard = keyboard;
		}

		/// <summary>
		/// 
		/// </summary>
		/// <param name="predicate"></param>
		/// <returns></returns>
		public IInputCallback If(Func<IInputContext, bool> predicate)
		{
			var callback = new InputCallback();
			var action = new InputAction(this, predicate, callback);
			callback.Action = action;
			_actions.Add(action);
			return callback;
		}

		public bool IsInitialized { get; private set; }

		public void Initialize()
		{
			//CurrentState = GetInputState();
			IsInitialized = true;
		}

		public void Update(UpdateContext context)
		{
			var previousState = CurrentState;
			CurrentState = GetInputState();
			var inputContext = new InputContext(CurrentState, previousState);
			_actions.Update(inputContext, new InputCallbackContext(context, CurrentState, previousState));
		}

		internal void Remove(IInputAction inputAction)
		{
			_actions.Remove(inputAction);
		}

		protected InputState GetInputState()
		{
			return new InputState
			{
#if !(WINDOWS_PHONE || ANDROID)
				MouseState = Mouse == null ? new MouseState() : Mouse.GetState(),
				MarqueeState = Marquee == null ? new MarqueeState() : Marquee.GetState(),
				GamePadState = GamePad == null ? new GamePadState() : GamePad.GetState(),
#endif
				TouchState = Touch == null ? new TouchCollection() : Touch.GetState(),
				KeyboardState = Keyboard == null ? new KeyboardState() : Keyboard.GetState(),
			};
		}

		#endregion
	}
}